package ccb.ygqd.inspur.card;

import android.content.Context;
import android.os.Bundle;

import com.ccb.stm.CCBStmCallBack;
import com.google.gson.Gson;
import com.siecomzg.bean.BankCardInfoBean;
import com.siecomzg.constconfig.ErrorDefine;
import com.siecomzg.tool.ByteTool;
import com.siecomzg.tool.LogUtil;
import com.siecomzg.transport.DeviceCallback;
import com.siecomzg.transport.SiecomDevice;


import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

import ccb.ygqd.inspur.common.ConstHF;


public class card {

    private Context mContext;
    private String TAG = card.class.getSimpleName();
    public card(Context context){
        mContext = context;
    }

    /**
     * 指定某个卡槽进行上电复位操作。
     * @param iSlotNum 0x00-0x0F： 为接触式的第一到第十六卡槽号；
     * 0x10-0x1F： 为 SAM 卡的第一到第十六卡槽号；
     * 0xFF： 为非接触式射频卡
     * @param strTimeout 默认为30秒
     * @return 正确返回时：aryRet[0]为“DRV0000000”，aryRet[1]为返回的上电复位数据。
     */
    public String[] PowerOn(int iSlotNum, String strTimeout){
        LogUtil.e(TAG,"调用 PowerOn iSlotNum == " + iSlotNum + " timeOut =  " + strTimeout );
        final String ret[] = new String[]{"","",""};
        if (!SiecomDevice.isConnected){
            ret[0] = ConstHF.ERR_NOT_CONN;
            ret[1] = ConstHF.ERR_DEV_ONT_CONN;
            return ret;
        }
        int timeOut = Integer.parseInt(strTimeout);
        final CountDownLatch latch = new CountDownLatch(1);
        int slot = iSlotNum;
        if (iSlotNum == 0xFF){ //非接
            slot = 1;
        }else {
            slot = 0; //插卡
        }
        SiecomDevice.iccPowerOn(slot, new DeviceCallback() {
            @Override
            public void onStart() {

            }

            @Override
            public void onError(Bundle bundle) {
                int code = bundle.getInt("code");
                if (code == ErrorDefine.MSR_CARD_TIME || code == ErrorDefine.IC_CRAD_TIMEOUT || code == ErrorDefine.TIME_OUT ||
                        code == ErrorDefine.PIC_CRAD_TIMEOUT || code == ErrorDefine.AUTO_CRAD_TIMEOUT)
                    ret[0] = ConstHF.ERR_TIME_OUT;
                else if (code == ErrorDefine.FINAN_OPERATE_CANCEL)
                    ret[0] = ConstHF.ERR_USER_CANCEL;
                else {
                    ret[0] = ConstHF.ERR_NO_CONDITION;
                }

                latch.countDown();
            }

            @Override
            public void onSuccess(Bundle bundle) {
                String atrStr = bundle.getString("data");
                ret[0] = ConstHF.ERR_SUCCESS;
                ret[1] = atrStr;
                latch.countDown();
            }

            @Override
            public void onCompleted(Bundle bundle) {

            }
        },timeOut*1000,false);

        try {
            latch.await(timeOut + 2, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        return ret;
    }

    /**
     * 指定某个卡槽进行下电操作，下电后关闭通信接口。关闭设备显示的卡机动画。
     * @param iSlotNum 0x00-0x0F： 为接触式的第一到第十六卡槽号；
     * 0x10-0x1F： 为 SAM 卡的第一到第十六卡槽号；
     * 0xFF： 为非接触式射频卡
     * @return aryRet[0]为错误代码，aryRet[1]为错误描述。
     */
    public String[] PowerOff(int iSlotNum){
        LogUtil.e(TAG,"PowerOff  iSlotNum == " + iSlotNum );
        final String ret[] = new String[]{"","",""};
        if (!SiecomDevice.isConnected){
            ret[0] = ConstHF.ERR_NOT_CONN;
            ret[1] = ConstHF.ERR_DEV_ONT_CONN;
            return ret;
        }
        int timeOut = 2;
        final CountDownLatch latch = new CountDownLatch(1);
        int slot = iSlotNum;
        if (iSlotNum == 0xFF){ //非接
            slot = 1;
        }else {
            slot = 0; //插卡
        }
        SiecomDevice.iccPowerOff(slot, new DeviceCallback() {
            @Override
            public void onStart() {

            }
            @Override
            public void onError(Bundle bundle) {

                latch.countDown();
            }

            @Override
            public void onSuccess(Bundle bundle) {
                ret[0] = ConstHF.ERR_SUCCESS;
                latch.countDown();
            }

            @Override
            public void onCompleted(Bundle bundle) {

            }
        },timeOut*1000,false);

        try {
            latch.await(timeOut + 1, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        return ret;
    }

    /**
     * 指定某个卡槽进行卡指令交互。
     * @param iSlotNum 指定SAM卡槽 取值范围10H-1FH
     * @param strInData 输入数据
     * @param iInDataLen 标识输入指令的长度
     * @param strTimeout 默认为30秒
     * @return 正确返回时：aryRet[0]为0x00。aryRet[1]、aryRet[2]标识指令执行后的返回数据的长度（aryRet[1]为高位，aryRet[2]为低位），aryRet[3]开始为指令执行后返回数据。
     * 错误返回时：aryRet[0]不为0x00。0x01代表通讯失败，0x02代表卡片无响应，0x04代表卡片未上电
     */
    public byte[] execCmd(int iSlotNum, byte[] strInData, int iInDataLen, String strTimeout){
        final byte[][] ret = new byte[1][1];
        final int[] outLen = new int[1];
        LogUtil.e(TAG,"iSlotNum == " + iSlotNum + " --- data == " + ByteTool.byte2hex(strInData));
        // 00A40400 0E   315041592E5359532E4444463031 00
        // 00A40400 000E 315041592E5359532E4444463031 0100
        //转换数据 长度进行转换

// 农信字符串解析为 APDU_SEND 00a40400 08a00000033301010100  //00a40400 07a000000004101000
        byte[] bytes = strInData;
        if(bytes.length < 4) {
            LogUtil.e(TAG, "APDU 参数错误");
            return ret[0];
        }
        byte[] apduSend;
        if (bytes.length == 4) { // 情况1：lc/le都为空
            apduSend = bytes;
        } else {
            byte le;
            if (bytes.length == 5) {// 情况2：lc 为空、le不为空
                apduSend = new byte[8];
                apduSend[5] = 0;
                le = 0;
            } else if (4 + 1 + bytes[4] == bytes.length) { // 情况3：lc 不为空，le为空
                apduSend = new byte[bytes.length + 3];
                apduSend[5] = bytes[4];
                System.arraycopy(bytes, 5, apduSend, 6, bytes.length - 5);
                le = 0;
            } else {// 情况3：lc/le都不为空
                apduSend = new byte[bytes.length + 2];
                apduSend[5] = bytes[4];
                System.arraycopy(bytes, 5, apduSend, 6, bytes.length - 6);
                le = bytes[bytes.length - 1];
            }
            apduSend[apduSend.length - 2] = (byte) (le == 0 ? 1 : 0);
            apduSend[apduSend.length - 1] = le;

            System.arraycopy(bytes, 0, apduSend, 0, 4);
            apduSend[4] = 0;
        }

        LogUtil.i(TAG, "转换成APDU_SEND结构:" + ByteTool.byte2hex(apduSend));



        int timeOut = Integer.parseInt(strTimeout);
        final CountDownLatch latch = new CountDownLatch(1);
        int slot = iSlotNum;
        SiecomDevice.icApdu(slot,ByteTool.byte2hex(apduSend), new DeviceCallback() {
            @Override
            public void onStart() {

            }

            @Override
            public void onError(Bundle bundle) {
                int code = bundle.getInt("code");
                if (code == ErrorDefine.MSR_CARD_TIME || code == ErrorDefine.IC_CRAD_TIMEOUT || code == ErrorDefine.TIME_OUT ||
                        code == ErrorDefine.PIC_CRAD_TIMEOUT || code == ErrorDefine.AUTO_CRAD_TIMEOUT){

                }
                else if (code == ErrorDefine.FINAN_OPERATE_CANCEL){

                }
                else {
                }

                latch.countDown();
            }

            @Override
            public void onSuccess(Bundle bundle) {

                String atrStr = bundle.getString("data");
                atrStr  = "00"+ atrStr;
                outLen[0] = atrStr.length()/2  ;
                ret[0] = new byte[outLen[0]];
                System.arraycopy(ByteTool.hexStr2Bytes(atrStr),0,ret[0],0,outLen[0] );
                int len = (ret[0][2] & 0xff) + 2; // 数据较长会溢出
                ret[0][1] = ByteTool.int2Bytes(len)[0];
                ret[0][2] = ByteTool.int2Bytes(len)[1];
                LogUtil.e(TAG,"==== " + atrStr);
                LogUtil.e(TAG,"最终数据 ==== " + ByteTool.byte2hex(ret[0]));
                latch.countDown();
            }

            @Override
            public void onCompleted(Bundle bundle) {
                latch.countDown();
            }
        },timeOut*1000,false);

        try {
            latch.await(timeOut + 2, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        return ret[0];
    }


    /**
     * 金融IC卡一体键盘的读写器可以支持磁条卡的读写，接触式或者非接触式IC卡读写。通过本接口可以获得读写器读写能力的类别信息。实现本接口时，默认5秒超时。
     * @return 正确返回时：aryRet[0]为“DRV0000000”。aryRet[1]为指令执行后的返回返回读写器能力值：
     * 2-只能接触式读写磁条卡；
     * 5-可接触式读写IC或者磁条卡；
     * 6-可接触也可非接触读写IC卡并可读写磁条卡。
     * 错误返回时：aryRet[0]为错误代码，aryRet[1]为错误描述。
     */
    public String[]  getCardRdWrtCap(){
        String[] ret = new String[]{ConstHF.ERR_SUCCESS,"5",""};
        return ret;
    }


    /**
     * 检测卡片具体放置在什么位置，包括接触式、非接触式或者刷磁条。调用此接口后，若卡片不在位，不能直接返回，应在超时时间内继续等待放置卡片，待检测到卡片在位后返回结果，直至超时。
     * @param strTimeout 单位秒，默认30秒
     * @return 正确返回时：aryRet[0]为“DRV0000000”。
     * aryRet[1]为检测到的卡片在位位置： 1-在接触式IC读卡位置；2-在非接触式读IC卡位置；0-在刷磁条的位置;当检测到是刷磁条时，
     * aryRet[2]返回读取到的2磁道信息，
     * aryRet[3]返回3磁道信息（若未读取到2或3磁道，对应的磁道数据可以为空，但是数组的位置不能变）
     */
    public String[]  detectCardPlace(String strTimeout){
        LogUtil.e(TAG,"detectCardPlace ---------------------------");
        final String ret[] = new String[]{"","","",""};
        if (!SiecomDevice.isConnected){
            ret[0] = ConstHF.ERR_NOT_CONN;
            ret[1] = ConstHF.ERR_DEV_ONT_CONN;
            return ret;
        }
        int timeOut = Integer.parseInt(strTimeout);
        final CountDownLatch latch = new CountDownLatch(1);
        int slot = 3;
        SiecomDevice.readCheckCard(slot, new DeviceCallback() {
            @Override
            public void onStart() {

            }

            @Override
            public void onError(Bundle bundle) {
                int code = bundle.getInt("code");
                if (code == ErrorDefine.MSR_CARD_TIME || code == ErrorDefine.IC_CRAD_TIMEOUT || code == ErrorDefine.TIME_OUT ||
                        code == ErrorDefine.PIC_CRAD_TIMEOUT || code == ErrorDefine.AUTO_CRAD_TIMEOUT)
                    ret[0] = ConstHF.ERR_TIME_OUT;
                else if (code == ErrorDefine.FINAN_OPERATE_CANCEL)
                    ret[0] = ConstHF.ERR_USER_CANCEL;
                else {
                    ret[0] = ConstHF.ERR_NO_CONDITION;
                }

                latch.countDown();
            }

            @Override
            public void onSuccess(Bundle bundle) {
                String atrStr = bundle.getString("data");
                ret[0] = ConstHF.ERR_SUCCESS;
                if (atrStr.equals("1") || atrStr.equals("2")){
                    ret[1] = atrStr;
                }else {
                    Gson gson = new Gson();
                    BankCardInfoBean bean = gson.fromJson(atrStr, BankCardInfoBean.class);
                    ret[1] = "0";
                    ret[2] = bean.twoMagneticTrack;
                    ret[3] = bean.threeMagneticTrack;
                }

                latch.countDown();
            }

            @Override
            public void onCompleted(Bundle bundle) {

            }
        },null,null,"",timeOut*1000,false);

        try {
            latch.await(timeOut + 2, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        return ret;
    }

    //    Common公共模块（移动外设）
//    本部分定义移动外设的公用接口，包括获取设备状态、复位设备。
//    各模块的定义如下：
//    密码键盘：PIN
//    非接触式IC卡：ICC
//    接触式IC卡：IC1（原为CDB）。
//    发卡箱：CDB
//    指纹仪：FIG
//    电子签名：YGB
//    磁条刷卡器：RDC
//    二代证：IDC
//    居民指纹仪：CFG

    /**
     *
     * @param strEventName 该参数为空或者null时，表示注册该模块的所有事件；有具体值时，表示只注册该模块的具体事件。
     * @param strTimeout 非负整数，事件监听的超时间隔；为0时表示一直监听
     * @param callBack 实现回调函数接口的类实例
     */

    public String mEventName ;
    public String mTimeOut;
    public CCBStmCallBack mCallBack;
    void registEvent(String strEventName, String strTimeout, CCBStmCallBack callBack){
        mEventName = strEventName;
        mTimeOut = strTimeout;
        mCallBack = callBack;
    }
}
